Imports System.IO
Imports System.Reflection

Public Class ccCardForm

    Private _Card As Card
    Private _DrawBack As Boolean
    Private _CardBackColor As CardBackColor
    Private _AllowDrag As Boolean
    Private myCardImage As Bitmap

    Private _CursorOffset As Point
    Private _Moving As Boolean

    ''' <summary>
    ''' Constructor used to create a visual card.
    ''' </summary>
    ''' <param name="myCard">The card.</param>
    ''' <param name="DrawBack">Specifies whether the front or the back should be drawn.</param>
    ''' <param name="myCardBackColor">The back color of the card.</param>
    ''' <remarks></remarks>
    Public Sub New(ByVal myCard As Card, ByVal DrawBack As Boolean, ByVal myCardBackColor As CardBackColor)

        ' This call is required by the Windows Form Designer.
        InitializeComponent()

        _Card = myCard
        _DrawBack = DrawBack
        _AllowDrag = True
        _CardBackColor = myCardBackColor
    End Sub

    Public Sub Flip()

        _DrawBack = IIf(_DrawBack, False, True)
        myCardImage = Nothing
        Me.Refresh()
    End Sub

    Public Property AllowDrag()
        Get
            Return _AllowDrag
        End Get
        Set(ByVal value)
            _AllowDrag = value
        End Set
    End Property

    Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)

        MyBase.OnPaint(e)

        ' Check to see if image was already loaded
        If IsNothing(myCardImage) Then

            Dim myImageStream As Stream = Nothing

            ' Check to see if we need the back or the front of a card.
            If _DrawBack Then

                myImageStream = Assembly.GetExecutingAssembly().GetManifestResourceStream _
                    (Assembly.GetExecutingAssembly().GetName.Name + _
                    ".Back " + _CardBackColor.ToString + ".png")
            Else

                myImageStream = Assembly.GetExecutingAssembly().GetManifestResourceStream _
                    (Assembly.GetExecutingAssembly().GetName.Name + _
                    "." + _Card.Value.ToString + " of " + _Card.Suit.ToString + ".png")
            End If

            myCardImage = New Bitmap(myImageStream)
        End If

        ' Set the size of the control.
        Me.Size = New Size(myCardImage.Width, myCardImage.Height)
        ' Draw the card.
        e.Graphics.DrawImage(myCardImage, 0, 0, myCardImage.Width, myCardImage.Height)
    End Sub

    Protected Overrides Sub OnPaintBackground(ByVal pe As System.Windows.Forms.PaintEventArgs)
        ' 
    End Sub

    Private Sub ccCardForm_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseDown

        If e.Button = Windows.Forms.MouseButtons.Left And _AllowDrag Then

            Me.BringToFront()
            _CursorOffset = e.Location
            _Moving = True
        End If
    End Sub

    Private Sub ccCardForm_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseMove

        If _Moving Then
            Dim clientPosition As Point = MyBase.Parent.PointToClient(System.Windows.Forms.Cursor.Position)
            Dim adjustedLocation As New Point(clientPosition.X - _CursorOffset.X, clientPosition.Y - _CursorOffset.Y)

            MyBase.Location = adjustedLocation
        End If
    End Sub

    Private Sub ccCardForm_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseUp

        _Moving = False
    End Sub
End Class

Partial Public Class Card

    ''' <summary>
    ''' Draws the card to a given Form.
    ''' </summary>
    ''' <param name="myForm">The Form to draw the card to.</param>
    ''' <param name="x">x-coordinate to draw the card.</param>
    ''' <param name="y">y-coordinate to draw the card.</param>
    ''' <param name="DrawBack">Specifies whether the front or the back should be drawn.</param>
    ''' <param name="myCardBackColor">The back color of the card.</param>
    ''' <remarks></remarks>
    Public Sub DrawToForm(ByRef myForm As Form, ByVal x As Integer, ByVal y As Integer, Optional ByVal DrawBack As Boolean = False, Optional ByVal myCardBackColor As CardBackColor = CardBackColor.Red)

        Dim myCardImage As New ccCardForm(Me, DrawBack, myCardBackColor)
        Dim myFoundCards() As Control = myForm.Controls.Find(Me.Value.ToString + " of " + Me.Suit.ToString, False)

        For Each myFoundCard As Control In myFoundCards
            If TypeOf myFoundCard Is ccCardForm Then myForm.Controls.Remove(myFoundCard)
        Next

        myCardImage.Name = Me.Value.ToString + " of " + Me.Suit.ToString
        myCardImage.Location = New Point(x, y)

        myForm.Controls.Add(myCardImage)
        myCardImage.BringToFront()
    End Sub

    ''' <summary>
    ''' Flips the card in a given Form.
    ''' </summary>
    ''' <param name="myForm">The Form where the card is in.</param>
    ''' <remarks></remarks>
    Public Sub Flip(ByVal myForm As Form)

        Dim myFoundCards() As Control = myForm.Controls.Find(Me.Value.ToString + " of " + Me.Suit.ToString, False)

        For Each myFoundCard As Control In myFoundCards

            If TypeOf myFoundCard Is ccCardForm Then CType(myFoundCard, ccCardForm).Flip()
        Next
    End Sub

    ''' <summary>
    ''' Returns the card with the given card name in a given Form.
    ''' </summary>
    ''' <param name="myForm">The Form where the card is in.</param>
    ''' <param name="MyCardString">The name of the card (eg. "Ace of Spades")</param>
    ''' <returns>Card as ccCardForm</returns>
    ''' <remarks></remarks>
    Public Shared Function Grab(ByVal myForm As Form, ByVal MyCardString As String) As ccCardForm

        CardsUtils.CheckCardString(MyCardString)

        Dim myFoundCards() As Control = myForm.Controls.Find(MyCardString, False)

        For Each myFoundCard As Control In myFoundCards

            If TypeOf myFoundCard Is ccCardForm Then Return CType(myFoundCard, ccCardForm)
        Next

        Return Nothing
    End Function
End Class

Partial Public Class Hand

    ''' <summary>
    ''' Draws the cards in the hand to a given Form.
    ''' </summary>
    ''' <param name="myForm">The Form to draw the cards to.</param>
    ''' <param name="x">x-coordinate to start drawing the cards.</param>
    ''' <param name="y">y-coordinate to start drawing the cards.</param>
    ''' <param name="DrawBack">Specifies whether the front or the back should be drawn.</param>
    ''' <param name="myCardBackColor">The back color of the cards.</param>
    ''' <remarks></remarks>
    Public Sub DrawToForm(ByRef myForm As Form, ByVal x As Integer, ByVal y As Integer, Optional ByVal DrawBack As Boolean = False, Optional ByVal myCardBackColor As CardBackColor = CardBackColor.Red)

        For Each myCard As Card In Me.Cards

            myCard.DrawToForm(myForm, x, y, DrawBack, myCardBackColor)

            x += 15
            y += 12
        Next
    End Sub

    ''' <summary>
    ''' Flips the cards in the hand in a given Form.
    ''' </summary>
    ''' <param name="myForm">The Form where the card is on.</param>
    ''' <remarks></remarks>
    Public Sub Flip(ByVal myForm As Form)

        For Each myCard As Card In Me.Cards

            myCard.Flip(myForm)
        Next
    End Sub

    ''' <summary>
    ''' Returns the card with the given card name in a given Form.
    ''' </summary>
    ''' <param name="myForm">The Form where the card is in.</param>
    ''' <param name="MyCardString">The name of the card (eg. "Ace of Spades")</param>
    ''' <returns>Card as ccCardForm</returns>
    ''' <remarks>If the card is not in the Hand, it returns Nothing.</remarks>
    Public Function GrabCard(ByVal myForm As Form, ByVal MyCardString As String) As ccCardForm

        CardsUtils.CheckCardString(MyCardString)

        For Each myCard As Card In Me.Cards

            If myCard.Value.ToString = CardsUtils.GetCardValueString(MyCardString) And _
            myCard.Suit.ToString = CardsUtils.GetCardSuitString(MyCardString) Then _
            Return Card.Grab(myForm, MyCardString)
        Next

        Return Nothing
    End Function
End Class

Partial Public Class CardsUtils

    ''' <summary>
    ''' Removes all cards from a given Form.
    ''' </summary>
    ''' <param name="myForm">The Form to remove the cards from.</param>
    ''' <remarks></remarks>
    Public Shared Sub ClearCards(ByRef myForm As Form)

        For i As Integer = myForm.Controls.Count - 1 To 0 Step -1

            If TypeOf myForm.Controls(i) Is ccCardForm Then myForm.Controls.RemoveAt(i)
        Next
    End Sub
End Class
